package com.handyshop.mall.gateway.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.handyshop.mall.gateway.constants.ErrorEnum;
import com.handyshop.mall.gateway.vo.TokenResultVo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * @author hs
 * @date 2020-12-02 15:53
 **/
@Component
public class JwtTokenFilter implements GlobalFilter, Ordered {

    private final String[] skipAuthUrls = new String[]{"/v2/api-docs", "/auth"};


    /**
     * 过滤器
     *
     * @param exchange exchange
     * @param chain    chain
     * @return Mono<Void>
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getURI().getPath();
        ServerHttpResponse resp = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();

        // 跳过不需要验证的路径
        for (String skipAuthUrl : skipAuthUrls) {
            if (url.contains(skipAuthUrl)) {
                return chain.filter(exchange);
            }
        }

        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (StrUtil.isEmpty(token)) {
            return chain.filter(exchange);
        }
       /* //从token中解析用户信息并设置到Header中去
        String realToken = token.replace("Bearer ", "").replace("bearer ", "");

        try {
            Claims claims = parseJwt(realToken);
            Object userId = claims.get("userId");
            // 保存用户信息到header中
            request.mutate().header("userId", userId.toString()).build();
        } catch (ExpiredJwtException e) {
            if (e.getMessage().contains("Allowed clock skew")) {
                return authError(resp, "认证过期");
            } else {
                return authError(resp, "认证失败");
            }
        } catch (Exception e) {
            return authError(resp, "认证失败");
        }*/
        return chain.filter(exchange);
    }

    /**
     * 认证错误输出
     *
     * @param resp 响应对象
     * @param msg  错误信息
     * @return Mono<Void>
     */
    private Mono<Void> authError(ServerHttpResponse resp, String msg) {
        resp.setStatusCode(HttpStatus.OK);
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        TokenResultVo<Object> tokenResultVo = TokenResultVo.failure(ErrorEnum.TOKEN_FAILURE, msg);
        DataBuffer buffer = resp.bufferFactory().wrap(JSONUtil.toJsonStr(tokenResultVo).getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(buffer));
    }

    /**
     * 解密jwt
     *
     * @param jwt jwt
     * @return Claims
     */
    public static Claims parseJwt(String jwt) {
        //得到DefaultJwtParser
        return Jwts.parser()
                //设置签名的秘钥
                .setSigningKey("handyShop".getBytes(StandardCharsets.UTF_8))
                //设置需要解析的jwt
                .parseClaimsJws(jwt).getBody();
    }

    @Override
    public int getOrder() {
        return -100;
    }

}
